from __future__ import annotations

from datetime import datetime
from typing import TYPE_CHECKING

from sqlalchemy import Boolean, DateTime, ForeignKey, JSON, String
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.db.base_class import BaseEntity

if TYPE_CHECKING:
  from .relationship import Relationship
  from .diary_comment import DiaryComment
  from .decision_preset import DecisionPreset


class User(BaseEntity):
  __tablename__ = "users"

  email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
  username: Mapped[str] = mapped_column(String(64), unique=True, index=True)
  nickname: Mapped[str | None] = mapped_column(String(64), nullable=True)
  password_hash: Mapped[str] = mapped_column(String(255))
  is_active: Mapped[bool] = mapped_column(Boolean, default=True)
  verified_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
  active_relationship_id: Mapped[int | None] = mapped_column(ForeignKey("relationships.id"), nullable=True)

  partner_profile: Mapped["PartnerProfile"] = relationship(
    back_populates="user", lazy="joined", uselist=False
  )
  diary_entries: Mapped[list["DiaryEntry"]] = relationship(back_populates="user", lazy="noload")
  anniversaries: Mapped[list["Anniversary"]] = relationship(back_populates="user", lazy="noload")
  cycle_logs: Mapped[list["CycleLog"]] = relationship(back_populates="user", lazy="noload")
  ai_sessions: Mapped[list["AISession"]] = relationship(back_populates="user", lazy="noload")
  diary_comments: Mapped[list["DiaryComment"]] = relationship("DiaryComment", back_populates="user", lazy="noload")
  decision_presets: Mapped[list["DecisionPreset"]] = relationship(
    "DecisionPreset", back_populates="user", lazy="noload"
  )
  initiated_relationships: Mapped[list["Relationship"]] = relationship(
    "Relationship", foreign_keys="Relationship.initiator_id", back_populates="initiator", lazy="noload"
  )
  accepted_relationships: Mapped[list["Relationship"]] = relationship(
    "Relationship", foreign_keys="Relationship.partner_id", back_populates="partner", lazy="noload"
  )


class PartnerProfile(BaseEntity):
  __tablename__ = "partner_profiles"

  user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), unique=True, index=True)
  partner_name: Mapped[str | None] = mapped_column(String(120), nullable=True)
  relationship_start_date: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  timezone: Mapped[str | None] = mapped_column(String(64))
  notification_prefs_json: Mapped[dict | None] = mapped_column(JSON, default=dict)

  user: Mapped[User] = relationship(back_populates="partner_profile", lazy="joined")
